package com.pattern.structural.composite;


import java.util.ArrayList;
import java.util.List;

/**
 * @Description  Composite demo by fruit plate example.
 * @Author Ping
 * @Date 2022/4/4 14:27
 **/
public class CompositeDemo {

    public static void main(String args[]) {

        Fruit fruitPlate = new FruitPlate() ;
        fruitPlate.addFruit(new Apple())
                   .addFruit(new FruitPlate()
                                    .addFruit(new Orange())
                                    .addFruit(new Apple()))
                   .addFruit(new Orange());

        fruitPlate.eat() ;



    }

}

/**
 * concepts:
 * 1. fruit
 * 2. fruitplate
 * 3. apple, banana ,
 */

/**
 * abstract concept: abstract fruit, includes fruit plate, and other specific fruits.
 */
abstract class Fruit {
    String name ;

    /**
     *
     */
    public abstract void eat() ;

    /**
     *
     * @param fruit
     * @return
     */
    public abstract Fruit addFruit(Fruit fruit);
}

/**
 * composite concept
 */
class FruitPlate extends Fruit {
    /**
     * composing other fruits.
     */
    List<Fruit> fruits ;

    public FruitPlate() {
        fruits = new ArrayList<>() ;
    }
    @Override
    public Fruit addFruit(Fruit fruit) {
        this.fruits.add(fruit) ;
        return this ;
    }
    @Override
    public void eat() {
        for (Fruit fruit : fruits) {
            // if withou COMPOSITE pattern, many if-else-if would be applied (BAD).
//            if (fruit instanceof  Apple) {
//                apple.eat() ;
//            } else if (fruit instanceof Orange) {
//                orange.eat() ;
//            }
            fruit.eat();
        }
       // this.fruits.stream().forEach(fruit -> fruit.eat());
    }
}

/**
 * specific concept :
 */
class Apple extends Fruit {
    public Apple() {
        this.name = "APPLE" ;
    }

    /**
     * detailed  logic for eating.
     */
    @Override
    public void eat() {
        System.out.println(this.name + " can eat .") ;
    }

    @Override
    public Fruit addFruit(Fruit fruit) {
        // here, could throw a new exception.
        System.out.println("The fruit is not plate, and can not be added other fruit .") ;
        return null;
    }
}

class Orange extends Fruit {
    public Orange() {
        this.name = "Orange" ;
    }

    @Override
    public void eat() {
        System.out.println(this.name + " can eat .") ;
    }

    @Override
    public Fruit addFruit(Fruit fruit) {
        System.out.println("The fruit is not plate, and can not be added other fruit .") ;
        return null;
    }
}
